﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

using WorkStation.Frameworks.Core;
using WorkStation.Frameworks.Core.Extensions;
using WorkStation.Frameworks.EasyBus.Handles;
using WorkStation.Frameworks.EasyBus.Extensions;
using WorkStation.Frameworks.EasyBus.Repositories;
using WorkStation.Frameworks.EasyBus.Plugins;
using WorkStation.Frameworks.EasyBus.Pipeline;
using WorkStation.Frameworks.EasyBus.Pipeline.Handles;
using WorkStation.Frameworks.EasyBus.Pipeline.Extensions;
using WorkStation.Frameworks.EasyBus.MessageQueue;

using Microsoft.Practices.ServiceLocation;

using Common.Logging;

namespace WorkStation.Frameworks.EasyBus
{
    public class EasyBus : IBus, IBusDataManager
    {
        #region 事件

        public event Action<BusActionContext, FailHandleResult> OnPublishFail;
        public event Action<BusActionContext, SuccessHandleResult> OnPublishSuccess;
        public event Action<BusActionContext> OnPublishBefore;
        public event Action<BusActionContext, IEnumerable<HandleResult>> OnPublishAfter;

        public event Action<BusActionContext, FailHandleResult> OnProcessFail;
        public event Action<BusActionContext, SuccessHandleResult> OnProcessSuccess;
        public event Action<BusActionContext> OnProcessBefore;
        public event Action<BusActionContext, IEnumerable<HandleResult>> OnProcessAfter;

        public event Action<BusActionContext, FailHandleResult> OnEventFail;

        public event Action<Exception> OnListenException;

        #endregion

        #region 私有变量

        protected IServer _server = null;
        protected IRegisterCenterRepository _registerCenterRepository = null;
        protected IHistoryCenterRepository _historyCenterRepository = null;

        #endregion

        #region WorkStation.Frameworks.EasyBus.IBusDataManager 成员

        /// <summary>
        /// 发送消息通道
        /// </summary>
        public IPipeline SendMessagePipeline { get; set; }

        /// <summary>
        /// 总线事件管道
        /// </summary>
        public IPipeline BusEventPipeline { get; set; }

        /// <summary>
        /// 监听器服务对象
        /// </summary>
        public IServer Server 
        {
            get 
            {
                if (this._server == null)
                {
                    throw new EasyBusException("监听服务组件为空，调用方法EasyBus.SetupServer()设置");
                }
                else 
                {
                    return this._server;
                }
            }
            set 
            {
                this._server = value;
            }
        }

        /// <summary>
        /// 总线所在服务器IP
        /// </summary>
        public string Ip { get; set; }

        /// <summary>
        /// 消息注册中心仓储组件
        /// </summary>
        public IRegisterCenterRepository RegisterCenterRepository 
        {
            get 
            {
                if (this._registerCenterRepository == null)
                {
                    throw new EasyBusException("消息注册中心仓储组件为空");
                }
                else 
                {
                    return this._registerCenterRepository;
                }
            }
            set 
            {
                this._registerCenterRepository = value;
            }
        }

        /// <summary>
        /// 消息历史记录中心仓储组件
        /// </summary>
        public IHistoryCenterRepository HistoryCenterRepository 
        {
            get 
            {
                if (this._historyCenterRepository == null)
                {
                    throw new EasyBusException("消息历史记录中心组件为空");
                }
                else 
                {
                    return this._historyCenterRepository;
                }
            }
            set 
            {
                this._historyCenterRepository = value;
            }
        }

        /// <summary>
        /// 日志
        /// </summary>
        public ILog Logger { get; set; }

        /// <summary>
        /// 数据
        /// </summary>
        public Dictionary<string, object> DataBag { get; set; }

        #endregion

        public static IBus GetInstance(string name) 
        {
            return new EasyBus(name); 
        }

        public static IBus GetInstance(string name, string node) 
        {
            return new EasyBus(name, node);
        }

        #region 构造函数

        protected EasyBus(string name) 
        {
            if (name.IsNullOrEmpty()) 
            {
                throw new ArgumentNullException("name");
            }

            this.Name = name;

            this.InitPipeline();

            this.Plugins = new List<IBusPlugin>();
            this.ConfigProvider = new List<IConfigProvider>();
            this.DataBag = new Dictionary<string, object>();

            this.Ip = Dns.GetHostAddresses(Dns.GetHostName())
                         .Where(v => v.AddressFamily == AddressFamily.InterNetwork)
                         .Select(v => v.ToString())
                         .JoinString(";");

            this.Logger = LogManager.GetLogger(this.Name);
        }

        protected EasyBus(string name, string node) : this(name)
        {
            // 如果节点名称为空，则认为不做负载，使用BusName作为节点名称
            if (node.IsNullOrEmpty())
            {
                this.NodeName = name;
            }
            else 
            {
                this.NodeName = node;
            }
        }

        #endregion

        #region 私有函数

        /// <summary>
        /// 初始化发送管道的事件（和 Bus 的事件关联）
        /// </summary>
        protected void InitSendMessagePipelineEvent()
        {
            if (this.OnPublishFail != null)
            {
                this.SendMessagePipeline.OnFail += (context, result) => this.OnPublishFail(context as BusActionContext, result);
            }

            if (this.OnPublishSuccess != null)
            {
                this.SendMessagePipeline.OnSuccess += (context, result) => this.OnPublishSuccess(context as BusActionContext, result);
            }

            if (this.OnPublishBefore != null)
            {
                this.SendMessagePipeline.OnPublishBefore += (context) => this.OnPublishBefore(context as BusActionContext);
            }

            if (this.OnPublishAfter != null)
            {
                this.SendMessagePipeline.OnPublishAfter += (context, result) => this.OnPublishAfter(context as BusActionContext, result);
            }
        }

        /// <summary>
        /// 初始化总线事件管道的事件
        /// </summary>
        protected void InitBusEventPipelineEvent() 
        {
            if (this.OnEventFail != null) 
            {
                this.BusEventPipeline.OnFail += (context, result) => this.OnEventFail(context as BusActionContext, result);
            }
        }

        protected void InitListenerEvent()
        {
            if (this._server != null)
            {
                foreach (IMessageListener listener in this.Server.Listeners.Values)
                {
                    if (this.OnListenException != null)
                    {
                        listener.OnListenException += ex => this.OnListenException(ex);
                    }

                    if (this.OnProcessAfter != null)
                    {
                        listener.OnProcessAfter += (context, result) => this.OnProcessAfter(context, result);
                    }

                    if (this.OnProcessBefore != null)
                    {
                        listener.OnProcessBefore += context => this.OnProcessBefore(context);
                    }

                    if (this.OnProcessFail != null)
                    {
                        listener.OnProcessFail += (context, result) => this.OnProcessFail(context, result);
                    }

                    if (this.OnProcessSuccess != null)
                    {
                        listener.OnProcessSuccess += (context, result) => this.OnProcessSuccess(context, result);
                    }
                }
            }
        }

        protected void InitPipeline() 
        {
            this.SendMessagePipeline = MethodPipeline<IPipeline>.Wrap(() => ServiceLocator.Current.GetInstance<IPipeline>())
                                                                .Error((args, res) => res.Result = new ObjectPipeline())
                                                                .Execute()
                                                                .Result;

            this.BusEventPipeline = MethodPipeline<IPipeline>.Wrap(() => ServiceLocator.Current.GetInstance<IPipeline>())
                                                             .Error((args, res) => res.Result = new ObjectPipeline())
                                                             .Execute()
                                                             .Result;
        }

        #endregion

        #region WorkStation.Frameworks.EasyBus.IBus 成员

        public string Name { get; set; }

        public string NodeName { get; set; }

        public List<IBusPlugin> Plugins { get; set; }

        public List<IConfigProvider> ConfigProvider { get; set; }

        public IBus Subscribe(string routeKey, IHandle handle)
        {
            this.SendMessagePipeline.Subscribe(routeKey, handle);

            return this;
        }

        public IBus Listen(string name, IEndpoint endpoint, int processThreadCount = 1)
        {
            name.IsNullOrEmpty().WhenTrue(() => { throw new ArgumentNullException("name"); });

            IMessageListener listener = null;

            if (!this.Server.Listeners.TryGetValue(name, out listener)) 
            {
                listener = new MessageListener(this, endpoint) 
                {
                    ProcessThreadCount = processThreadCount,
                    Name = name
                };

                this.Server.RegisterListener(listener);
            }

            return this;
        }

        public IBus SetListenerProcess(string name, string routeKey, ProcessHandle handle) 
        {
            IMessageListener listener = null;

            if (this.Server.Listeners.TryGetValue(name, out listener))
            {
                handle.Listener = listener; ;
                listener.ReceiveMessagePipeline.Subscribe(routeKey, handle);
            }
            else 
            {
                throw new EasyBusException("给定的监听器名称【{0}】没有设置，使用【IBus.Listen()】方法注册监听器".Fmt(name));
            }

            return this;
        }

        public IEnumerable<HandleResult> Publish(object msg)
        {
            if (this.SendMessagePipeline != null) 
            {
                IEnumerable<HandleResult> results = null;

                BusActionContext context = new BusActionContext() { Bus = this };

                if (msg is Event) 
                {
                    context.Input = msg;

                    results = this.BusEventPipeline.Publish(context);
                }
                else if (msg is Message)
                {
                    context.Input = msg;
                    context.RouteKey = (msg as Message).RouteKey;

                    results = this.SendMessagePipeline.Publish(context);
                }
                else 
                {
                    new Message(msg).Continue(v => context.Input = v).Continue(v => context.RouteKey = v.RouteKey);

                    results = this.SendMessagePipeline.Publish(context);
                }

                return results;
            }

            return null;
        }

        public IBus Start()
        {
            this.Plugins.OrderBy(v => v.Index).ForEach(v => v.Register(this));

            // 将总线的事件与发送管道事件关联
            this.InitSendMessagePipelineEvent();

            // 将总线的事件与总线事件管道事件关联
            this.InitBusEventPipelineEvent();

            // 将总线的时间与监听器事件关联
            this.InitListenerEvent();

            if (this._server != null) 
            {
                this.Server.Start();
            }

            return this;
        }

        /// <summary>
        /// 安装监听服务器对象（还可以从IOC中添加，都没有默认使用<see cref="WorkStation.Frameworks.EasyBus.DefaultServer"/>）
        /// </summary>
        /// <param name="server">监听服务器对象</param>
        /// <returns></returns>
        public IBus SetupServer(IServer server = null) 
        {
            IBusDataManager manager = this as IBusDataManager;

            if (server != null)
            {
                manager.Server = server;
            }
            else 
            {
                manager.Server = MethodPipeline<IServer>.Wrap(() => ServiceLocator.Current.GetInstance<IServer>())
                                                        .Error((args, res) => res.Result = new DefaultServer())
                                                        .Execute()
                                                        .Result;
            }
            
            return this;
        }

        #endregion

        #region IDisposable 成员

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            if (this.Server != null) 
            {
                this.Server.Stop();
            }

            this.Server = null;

            if (this._historyCenterRepository != null) 
            {
                this._historyCenterRepository.Dispose();
            }

            if (this._registerCenterRepository != null) 
            {
                this._registerCenterRepository.Dispose();
            }
        }

        #endregion
    }
}
